<template>
  <div id="map"></div>
  <div class="overlay"></div>
  <div v-if="props.drawType" class="geoStyle-option">
    <h4>请选择绘画的样式</h4>
    <div>
      <div
        v-if="
          props.drawType === 'Polygon' ||
          props.drawType === 'Rectangle' ||
          props.drawType === 'Circle' ||
          props.drawType === 'zdy'
        "
        class="text"
      >
        边框颜色:
      </div>
      <div v-else class="text">颜色:</div>
      <el-color-picker v-model="colorValue"></el-color-picker>
    </div>
    <div v-if="props.drawType === 'Point'">
      <div class="text">半径:</div>
      <el-input
        v-model="radiusValue"
        calss="radius-input"
        type="number"
      ></el-input>
    </div>
    <div v-else-if="props.drawType === 'LineString'">
      <div class="text">线宽:</div>
      <el-input
        v-model="lineWidth"
        calss="radius-input"
        type="number"
      ></el-input>
    </div>
    <div
      v-else-if="
        props.drawType === 'Polygon' ||
        props.drawType === 'Rectangle' ||
        props.drawType === 'Circle' ||
        props.drawType === 'zdy'
      "
    >
      <div class="text">填充颜色:</div>
      <el-color-picker v-model="fillColor"></el-color-picker>
      <div class="text text-fill">边框宽度:</div>
      <el-input
        v-model="lineWidth"
        calss="radius-input"
        type="number"
      ></el-input>
    </div>
    <el-button @click="clearCanvas">清除绘画内容</el-button>
    <el-button @click="closeDraw">退出绘画状态</el-button>
  </div>
  <div v-show="showzoom" class="currentZoom">当前的缩放级别是：{{ zoom }}</div>
</template>

<script setup>
//vue相关导入
import { ref, onMounted, watch } from 'vue'
//openlayers相关导入
import 'ol/ol.css' // 引入openlayers样式文件
import { View, Map } from 'ol'
import TileLayer from 'ol/layer/Tile'
import XYZ from 'ol/source/XYZ'
import VectorLayer from 'ol/layer/Vector'
import VectorSource from 'ol/source/Vector'
import GeoJSON from 'ol/format/GeoJSON'
import { Circle as CircleStyle, Fill, Style, Stroke } from 'ol/style'
import Draw from 'ol/interaction/Draw'
import { createBox } from 'ol/interaction/Draw'
import Overlay from 'ol/Overlay'
import { getLength, getArea, getDistance } from 'ol/sphere'
import Feature from 'ol/Feature'
import Icon from 'ol/style/Icon'
import Text from 'ol/style/Text'
import Point from 'ol/geom/Point.js'
import Cluster from 'ol/source/Cluster'
//ol-ext相关导入
import ol_featureAnimation_Drop from 'ol-ext/featureanimation/Drop.js'
import ol_layer_AnimatedCluster from 'ol-ext/layer/AnimatedCluster.js'
//axios导入
import axios from 'axios'
//element-plus相关导入
import { ElMessage } from 'element-plus'

const props = defineProps({
  initCity: {
    type: Object,
    required: true,
  },
  searchCity: {
    type: String,
    required: true,
  },
  drawType: {
    type: String,
    required: true,
  },
  drawImage: {
    type: String,
    required: true,
  },
})
const emit = defineEmits(['closeDraw', 'updateZoom'])

const map = ref(null)
//定义当前draw的状态
const currentDraw = ref(null)
const AllVectorLayer = ref([])

//覆盖物
let MarkOverlay = ref(null)

const center = ref([]) //当前视图中心
const zoom = ref(4) //当前视图缩放级别
let showzoom = ref(false) //是否显示当前的缩放级别
let timerZoom = ref(null) //定时器

const initVectorLayer = ref(null) //初始化城市的矢量图层

//绘画要素的样式
const colorValue = ref('#ff0000') //颜色 以及面域边框的颜色
const radiusValue = ref(20) //点要素的半径
const lineWidth = ref(2) //线宽 以及面域的边框
//面域的样式
const fillColor = ref('#3b6df9') //面域填充颜色

//绘画icon相关变量
let iconLayer = ref(null) // 基础图层（存放原始图标）
let clusterLayer = ref(null) // 聚合图层（显示聚合效果）
let iconSource = ref(null) // 基础数据源
let clickListener = null // 点击事件监听

//console.log('init', props.initCity.features) //第一次打印是undefined  第二次开始正常打印
//console.log('center', center)

//监听initCity的变化，初始化地图
watch(
  () => props.initCity,
  () => {
    if (props) {
      initMap()
      // console.log(map.value.getView().values_.zoom)
    }
  },
  { deep: true }
)

//监听zoom的变化，改变initVectorLayer的显示隐藏状态  同时 当zoom变化的时候，currentZoom才显示出来
watch(
  () => zoom.value,
  (newVlaue, oldValue) => {
    if (zoom.value > 10) {
      initVectorLayer.value.setVisible(false)
    } else {
      initVectorLayer.value.setVisible(true)
    }
    if (newVlaue !== oldValue) {
      showzoom.value = true
      //清除之前的定时器
      clearTimeout(timerZoom.value)
    }

    //设置一个定时器，当变化的时候，显示dom元素，在2s之后关系
    timerZoom.value = setTimeout(() => {
      showzoom.value = false
    }, 2000)
  }
)

//监听searchCity的变化，跳转中心点
watch(
  () => props.searchCity,
  () => {
    if (props.searchCity) {
      jumpCenter()
    }
  },
  { deep: true }
)

//监听drawType的变化，实现绘制图形
watch(
  () => props.drawType,
  () => {
    if (props.drawType) {
      drawType(props.drawType)
    }
  },
  { deep: true }
)
//监听样式的改变 修改样式重新绘画
watch(
  () => [colorValue.value, radiusValue.value, lineWidth.value, fillColor.value],
  () => {
    //先移除之前的Draw绘画
    if (currentDraw.value) {
      map.value.removeInteraction(currentDraw.value)
      currentDraw.value = null
    }

    if (props.drawType === 'Point') {
      //如果样式参数发生变化，新建一个图层和数据源，在新的图层上绘制新的样式
      const newPointLayer = new VectorLayer({
        source: new VectorSource(),
        style: new Style({
          image: new CircleStyle({
            radius: radiusValue.value,
            fill: new Fill({ color: colorValue.value }),
          }),
        }),
      })
      map.value.addLayer(newPointLayer)

      currentDraw.value = new Draw({
        source: newPointLayer.getSource(),
        type: 'Point',
      })
      map.value.addInteraction(currentDraw.value)
    } else if (props.drawType === 'LineString') {
      //如果样式参数发生变化，新建一个图层和数据源，在新的图层上绘制新的样式
      const newLineLayer = new VectorLayer({
        source: new VectorSource(),
        style: new Style({
          stroke: new Stroke({
            width: lineWidth.value,
            color: colorValue.value,
          }),
        }),
      })
      map.value.addLayer(newLineLayer)

      currentDraw.value = new Draw({
        source: newLineLayer.getSource(),
        type: 'LineString',
      })
      map.value.addInteraction(currentDraw.value)
    } else if (props.drawType === 'Polygon') {
      //如果样式参数发生变化，新建一个图层和数据源，在新的图层上绘制新的样式
      const newPolygonLayer = new VectorLayer({
        source: new VectorSource(),
        style: new Style({
          fill: new Fill({
            color: fillColor.value,
          }),
          stroke: new Stroke({
            width: lineWidth.value,
            color: colorValue.value,
          }),
        }),
      })
      map.value.addLayer(newPolygonLayer)

      currentDraw.value = new Draw({
        source: newPolygonLayer.getSource(),
        type: 'Polygon',
      })
      map.value.addInteraction(currentDraw.value)
    } else if (props.drawType === 'Rectangle') {
      //如果样式参数发生变化，新建一个图层和数据源，在新的图层上绘制新的样式
      const newRectangleLayer = new VectorLayer({
        source: new VectorSource(),
        style: new Style({
          fill: new Fill({
            color: fillColor.value,
          }),
          stroke: new Stroke({
            width: lineWidth.value,
            color: colorValue.value,
          }),
        }),
      })
      map.value.addLayer(newRectangleLayer)

      currentDraw.value = new Draw({
        source: newRectangleLayer.getSource(),
        type: 'Circle',
        geometryFunction: createBox(),
      })
      map.value.addInteraction(currentDraw.value)
    } else if (props.drawType === 'Circle') {
      //如果样式参数发生变化，新建一个图层和数据源，在新的图层上绘制新的样式
      const newCircleLayer = new VectorLayer({
        source: new VectorSource(),
        style: new Style({
          fill: new Fill({
            color: fillColor.value,
          }),
          stroke: new Stroke({
            width: lineWidth.value,
            color: colorValue.value,
          }),
        }),
      })
      map.value.addLayer(newCircleLayer)

      currentDraw.value = new Draw({
        source: newCircleLayer.getSource(),
        type: 'Circle',
      })
      map.value.addInteraction(currentDraw.value)
    } else if (props.drawType === 'zdy') {
      //如果样式参数发生变化，新建一个图层和数据源，在新的图层上绘制新的样式
      const newCircleLayer = new VectorLayer({
        source: new VectorSource(),
        style: new Style({
          fill: new Fill({
            color: fillColor.value,
          }),
          stroke: new Stroke({
            width: lineWidth.value,
            color: colorValue.value,
          }),
        }),
      })
      map.value.addLayer(newCircleLayer)

      currentDraw.value = new Draw({
        source: newCircleLayer.getSource(),
        type: 'Polygon',
        freehand: true, // 允许绘制任意形状
      })
      map.value.addInteraction(currentDraw.value)
    }
  }
)

//监听drawImage的变化，实现绘制图片
watch(
  () => props.drawImage,
  () => {
    if (props.drawImage) {
      drawIamge()
    }
  },
  { deep: true }
)

//监听drawType的变化，实现绘制图形
//封装初始化地图的方法
const initMap = () => {
  center.value = props.initCity.features.properties.center
  // console.log(center.value)
  const view = new View({
    center: center.value,
    zoom: zoom.value,
    projection: 'EPSG:4326',
  })
  map.value = new Map({
    target: 'map',
    view: view,
    layers: [
      new TileLayer({
        source: new XYZ({
          url: 'http://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}',
        }),
      }),
    ],
  })
  //change:resolution   监听缩放级别变化
  view.on('change:resolution', () => {
    zoom.value = view.getZoom().toFixed(2) // 更新 zoom 值
    emit('updateZoom', zoom.value)
  })

  // console.log(props.initCity.features)
  //在初始化地图完成之后，创建一个初始化矢量地图，用来加载initCity的features
  const format = new GeoJSON()
  const initfeatures = format.readFeatures(props.initCity.features, {
    featureProjection: 'EPSG:4326',
  })

  initVectorLayer.value = new VectorLayer({
    source: new VectorSource({
      features: initfeatures,
    }),
    style: new Style({
      stroke: new Stroke({
        color: 'red',
        width: 2,
      }),
      fill: new Fill({
        color: 'rgba(255,0,0, 0.5)',
      }),
    }),
  })
  map.value.addLayer(initVectorLayer.value)

  //地图初始化 添加动画zoom缩放
  const initview = map.value.getView()
  initview.animate({
    zoom: 8,
    duration: 2000,
  })
  map.value.render()

  //在地图加载完成的时候，就新建一个聚合图层和聚合的数据源
  iconSource.value = new VectorSource()
  // 创建聚合数据源
  const clusterSource = new Cluster({
    source: iconSource.value,
    distance: 40,
  })

  // 创建聚合图层
  clusterLayer.value = new ol_layer_AnimatedCluster({
    name: 'cluster',
    source: clusterSource,
    style: (feature) => IconClusterStyle(feature),
  })
  map.value.addLayer(clusterLayer.value) // 添加聚合图层到地图
}

//接受props中的serachcity，实现跳转对应的中心点
const jumpCenter = async () => {
  const searchName = props.searchCity
  //根据名字 获取对应的经纬度坐标
  const res = await axios.get(
    `https://restapi.amap.com/v3/geocode/geo?address=${searchName}&key=4f18e9fff456078b2892d6138e1adc90`
  )
  //console.log(res.data)
  if (res.data.status === '1' && res.data.count === '1') {
    // console.log(res.data.geocodes[0].location) //114.304569,30.593354
    center.value = [
      res.data.geocodes[0].location.split(',')[0],
      res.data.geocodes[0].location.split(',')[1],
    ]
    //console.log('城市名称', searchName, '中心点', center.value)

    //跳转地图中心点
    let view = map.value.getView()
    view.animate({
      center: center.value,
      duration: 1000,
    })
    map.value.render()
  } else {
    ElMessage.error('没有找到该城市')
  }
}

//实现绘制图形   !!!这里的代码有重复部分，可以单独封装出来 调用【待实现】
const drawType = (type) => {
  //移除current的交互
  if (currentDraw.value) {
    map.value.removeInteraction(currentDraw.value)
    currentDraw.value = null
  }

  //新建覆盖物  用来计算draw的长度或者面积
  MarkOverlay.value = new Overlay({
    element: document.querySelector('.overlay'),
  })
  map.value.addOverlay(MarkOverlay.value)

  //console.log(type)
  if (type === 'Point') {
    //console.log(colorValue.value)
    //创建一个矢量图层来放置绘制的图形
    let PointLayer = new VectorLayer({
      source: new VectorSource(),
      style: new Style({
        image: new CircleStyle({
          radius: radiusValue.value,
          fill: new Fill({ color: colorValue.value }),
        }),
      }),
    })
    map.value.addLayer(PointLayer)
    currentDraw.value = new Draw({
      source: PointLayer.getSource(),
      type: type,
    })
    map.value.addInteraction(currentDraw.value)
  } else if (type === 'LineString') {
    //创建线的矢量图层和数据源
    const LineLayer = new VectorLayer({
      source: new VectorSource(),
      style: new Style({
        stroke: new Stroke({
          width: lineWidth.value,
          color: colorValue.value,
        }),
      }),
    })
    map.value.addLayer(LineLayer)
    currentDraw.value = new Draw({
      source: LineLayer.getSource(),
      type: type,
    })
    map.value.addInteraction(currentDraw.value)

    currentDraw.value.on('drawend', function (e) {
      let feature = e.feature
      let geometry = feature.getGeometry()
      let coordinates = geometry.getCoordinates()
      let length = getLength(geometry, { projection: 'EPSG:4326' })
      //console.log(length)
      length = (length / 1000).toFixed(2)

      const element = document.querySelector('.overlay')
      element.innerHTML = '总距离为: ' + length + '公里'
      const coordinate = coordinates[geometry.getCoordinates().length - 1]
      MarkOverlay.value.setPosition(coordinate)
    })
  } else if (type === 'Polygon') {
    //创建面图层和数据源
    const PolygonLayer = new VectorLayer({
      source: new VectorSource(),
      style: new Style({
        fill: new Fill({
          color: fillColor.value,
        }),
        stroke: new Stroke({
          width: lineWidth.value,
          color: colorValue.value,
        }),
      }),
    })
    map.value.addLayer(PolygonLayer)
    currentDraw.value = new Draw({
      source: PolygonLayer.getSource(),
      type: type,
    })
    map.value.addInteraction(currentDraw.value)

    currentDraw.value.on('drawend', function (e) {
      let feature = e.feature
      let geometry = feature.getGeometry()
      let coordinates = geometry.getCoordinates()
      let area = getArea(geometry, { projection: 'EPSG:4326' })

      area = (area / 1000000).toFixed(2)
      // console.log('area', area)
      const element = document.querySelector('.overlay')
      element.innerHTML = '总面积为: ' + area + '平方公里'
      const coordinate = coordinates[geometry.getCoordinates().length - 1]
      //console.log('coordinate', coordinate)
      const _coordinate = coordinate[coordinate.length - 2]
      //console.log('_coordinate', _coordinate)
      MarkOverlay.value.setPosition(_coordinate)
    })
  } else if (type === 'Rectangle') {
    //创建矩形图层和数据源
    const RectangleLayer = new VectorLayer({
      source: new VectorSource(),
      style: new Style({
        fill: new Fill({
          color: fillColor.value,
        }),
        stroke: new Stroke({
          width: lineWidth.value,
          color: colorValue.value,
        }),
      }),
    })
    map.value.addLayer(RectangleLayer)
    currentDraw.value = new Draw({
      source: RectangleLayer.getSource(),
      type: 'Circle',
      geometryFunction: createBox(),
    })
    map.value.addInteraction(currentDraw.value)

    currentDraw.value.on('drawend', function (e) {
      let feature = e.feature
      let geometry = feature.getGeometry()
      // console.log('geometry', geometry)
      let area = getArea(geometry, { projection: 'EPSG:4326' })

      area = (area / 1000000).toFixed(2)
      // console.log('area', area)
      const element = document.querySelector('.overlay')
      element.innerHTML = '总面积为: ' + area + '平方公里'
      const coordinate = geometry.getInteriorPoint().getCoordinates()
      //console.log('coordinate', coordinate)
      MarkOverlay.value.setPosition(coordinate)
    })
  } else if (type === 'Circle') {
    //创建圆图层和数据源
    const CircleLayer = new VectorLayer({
      source: new VectorSource(),
      style: new Style({
        fill: new Fill({
          color: fillColor.value,
        }),
        stroke: new Stroke({
          width: lineWidth.value,
          color: colorValue.value,
        }),
      }),
    })
    map.value.addLayer(CircleLayer)
    currentDraw.value = new Draw({
      source: CircleLayer.getSource(),
      type: 'Circle',
    })
    map.value.addInteraction(currentDraw.value)

    currentDraw.value.on('drawend', function (e) {
      let feature = e.feature
      let circle = feature.getGeometry()
      // console.log(circle)
      const center = circle.getCenter()
      const radiusDeg = circle.getRadius()
      const edgePoint = [center[0] + radiusDeg, center[1]]
      let radius = getDistance(center, edgePoint)
      // console.log('半径', radius)
      radius = (radius / 1000).toFixed(2)
      const area = (Math.PI * radius * radius).toFixed(2)
      // console.log('面积', area)
      const element = document.querySelector('.overlay')
      element.innerHTML = '半径: ' + radius + '公里 面积: ' + area + '平方公里'
      const coordinate = center
      MarkOverlay.value.setPosition(coordinate)
    })
    /*    function getRadiusInMeters(circle) {
      const center = circle.getCenter()
      const radiusDeg = circle.getRadius()
      const edgePoint = [center[0] + radiusDeg, center[1]]
      return getDistance(center, edgePoint)
    }
    console.log(getRadiusInMeters(currentDraw.value))
 */
  } else if (type === 'zdy') {
    //创建自定义图层和数据源
    const zdyLayer = new VectorLayer({
      source: new VectorSource(),
      style: new Style({
        fill: new Fill({
          color: fillColor.value,
        }),
        stroke: new Stroke({
          width: lineWidth.value,
          color: colorValue.value,
        }),
      }),
    })
    map.value.addLayer(zdyLayer)
    currentDraw.value = new Draw({
      source: zdyLayer.getSource(),
      type: 'Polygon',
      freehand: true, // 允许绘制任意形状
    })
    map.value.addInteraction(currentDraw.value)

    currentDraw.value.on('drawend', function (e) {
      let feature = e.feature
      let geometry = feature.getGeometry()
      let coordinates = geometry.getCoordinates()
      let area = getArea(geometry, { projection: 'EPSG:4326' })

      area = (area / 1000000).toFixed(2)
      // console.log('area', area)
      const element = document.querySelector('.overlay')
      element.innerHTML = '总面积为: ' + area + '平方公里'
      const coordinate = coordinates[geometry.getCoordinates().length - 1]
      //console.log('coordinate', coordinate)
      const _coordinate = coordinate[coordinate.length - 2]
      //console.log('_coordinate', _coordinate)
      MarkOverlay.value.setPosition(_coordinate)
    })
  }
}

//清除绘画内容
const clearCanvas = () => {
  const vectorLayers = map.value
    .getLayers()
    .getArray()
    .filter((layer) => layer instanceof VectorLayer)

  vectorLayers.forEach((layer) => {
    layer.getSource().clear() // 清空数据源
  })

  // 移除当前绘制交互
  if (currentDraw.value) {
    map.value.removeInteraction(currentDraw.value)
    currentDraw.value = null
  }
  MarkOverlay.value.setPosition(undefined) // 清空覆盖物
}
//退出绘画状态
const closeDraw = () => {
  clearCanvas()
  emit('closeDraw')
  MarkOverlay.value.setPosition(undefined) // 清空覆盖物
}

//实现drawImage的功能
const drawIamge = () => {
  // 清理旧的事件监听器
  if (clickListener) {
    map.value.un('click', clickListener.listener)
    clickListener = null
  }

  // 添加新的点击事件
  clickListener = map.value.on('click', (e) => {
    const iconFeature = new Feature({
      geometry: new Point(e.coordinate),
      name: props.drawImage,
    })
    iconFeature.setStyle(
      new Style({
        image: new Icon({
          src: `/${props.drawImage}.png`,
          scale: 0.15,
          anchor: [0.5, 1],
        }),
      })
    )
    iconSource.value.addFeature(iconFeature)

    // 添加动画效果 【动画效果实现，要素重复，逻辑待更新】
    clusterLayer.value.animateFeature(iconFeature, [
      new ol_featureAnimation_Drop({
        speed: 1,
        duration: 2000,
        side: 'top',
      }),
    ])
  })
}

//封装函数  实现聚合图层的效果
const IconClusterStyle = (clusterFeature) => {
  //  参数为聚合后的要素对象
  const features = clusterFeature.get('features') // 获取聚合内的所有要素
  const count = features.length
  const singleFeature = features[0]
  if (count === 1) {
    return new Style({
      image: new Icon({
        src: `/${singleFeature.get('name')}.png`,
        scale: 0.15,
        anchor: [0.5, 1],
      }),
      text: new Text({
        text: singleFeature.get('name'),
        font: '12px sans-serif',
        fill: new Fill({ color: 'black' }),
        offsetY: 10,
      }),
    })
  } else {
    return new Style({
      image: new CircleStyle({
        radius: 15,
        stroke: new Stroke({ color: '#fff', width: 2 }),
        fill: new Fill({ color: '#4164fc' }),
      }),
      text: new Text({
        text: count.toString(),
        font: '12px sans-serif',
        fill: new Fill({ color: 'white' }),
        offsetY: 0,
      }),
    })
  }
}
</script>

<style lang="scss" scoped>
#map {
  width: 100vw;
  height: 90vh;
  background-color: transparent;
}
.geoStyle-option {
  position: fixed;
  top: 100px;
  left: 100px;
  /*   width: 300px;
  height: 100px; */
  background-color: #fff;

  border-radius: 5px;
  padding: 20px;
  box-shadow: 0 0 10px rgba(59, 109, 249, 0.5);
  h4 {
    margin: 0 0 10px 0;
    font-weight: 600;
    color: #474747;
  }
  div {
    display: flex;
    align-items: center;
    margin-bottom: 5px;
    color: #424242;
    .text {
      margin-right: 20px;
    }
    .text-fill {
      margin-left: 20px;
    }
    .el-input {
      width: 70px;
    }
    .el-color-picker {
      margin-right: 20px;
    }
  }
}
.overlay {
  background-color: #fff;
  padding: 20px;
  border-radius: 5px;
  box-shadow: 0 0 10px rgba(59, 109, 249, 1);
}
.currentZoom {
  position: fixed;
  top: 60px;
  right: 700px;
  display: block;
  background-color: #ffffff;
  border-radius: 5px;
  padding: 10px;
  box-shadow: 0 0 20px rgba(59, 109, 249, 0.8);
  border: 2px solid rgba(59, 109, 249, 0.9);
}
</style>
